Questo modulo ha lo scopo di introdurvi alle basi della programmazione ed alla sua applicazione al campo scientifico.
Nel corso di questo modulo useremo due linguaggi di programmazione di alto livello, python e matlab.
Oltre a questi linguaggi ne esistono moltissimi altri, tutti appropriati all'uso:
Vedremo anche nel corso delle lezioni vari concetti che vi torneranno utili qualsiasi sarà il linguaggio con cui deciderete di lavorare.
In particolare oggi inizieremo discutendo il controllo di versione.
Ma prima, che cosa sono i linguaggi di alto livello, e perché vale la pena usarli?
Il termine "linguaggio di alto livello" è una forma colloquiale, non definita in senso formale, ma sono presenti varie proprietà che li accumunano.
Lo scopo comune è rendere molto più semplice lo sviluppo di codice. Tutto il tempo che non passo a cercare di ricordare come inizializzare un puntatore, lo posso spendere a rendere le mie analisi più interessanti
vediamo un esempio che possa aiutare a capire che cosa intendo, usando il Python
import os
filenames = [filename for filename in os.listdir('.') if filename.endswith('.txt')]
for filename in filenames:
os.rename(filename, filename.replace('.txt', '.csv'))
Vedete che il codice, anche senza commenti, è chiaro e leggibile, ed esprimo dei concetti molto complicati in poche linee di codice
Oggi come oggi chi fa ricerca deve per forza scrivere del codice.
Ci viene insegnato a scrivere codice ma non a prendercene cura.
Un modo di dire comune nel campo dello sviluppo è:
Scrivi il tuo codice come se la prossima persona a doversene occupare fosse uno psicopatico che sa dove abiti.
Considerando il numero di progetti che lo scienziato medio deve seguire al giorno d'oggi, lo psicopatico in questione potreste essere voi!
Cosa è necessario per avere del codice salubre?
Durante questo corso cercheremo non solo di insegnarvi la programmazione di alto livello, ma anche come gestire i vostri progetti in modo da limitare il numero di momenti di terrore, disperazione e sconforto che avreste altrimenti.
Se pensate che stia scherzando, immaginate le seguenti situazioni:
Questi sono solo alcuni esempi, assolutamente visti capitare nella vita reale, fonti di stress facilmente evitabile.
Le procedure che vi insegneremo non possono ovviamente contrastare la sfortuna cieca, ma possono arginarne gli effetti nocivi ed evitare il disastro totale.
E sono tutte abbastanza semplici perché usarle non sia uno sforzo immane!
il concetto dietro questi esempi e questi strumenti è la corretta gestione dei metadata (dati a proposito dei dati).
Considerate un pezzo di programma come quello di prima. Il nome delle variabili è assolutamente arbitrario, e non influenza in nessun modo il risultato del programma, ma se cambiassi i nomi a caso il codice, seppure corretto, sarebbe incomprensibile, difficile da modificare e in poco tempo dimenticherei completamente il suo scopo d'essere.
Nel codice di solito si usano nomi coerenti e commenti, ma c'è molto altro di cui possiamo tenere traccia se ne siamo consci.
Avete mai avuto diverse copie di un file, chiamate doc_v1, doc_v2 e così via?
Bene, quello è un controllo di versione manuale. Grazie al computer possiamo fare di meglio.
Possiamo tenere traccia di tutto quello che succede, tornare indietro ad un momento qualsiasi, vedere le differenze fra due versioni successive ed anche tenere "universi paralleli" di versioni alternative.
I programmi che permettono di farlo sono i Sistemi di Controllo di Versione.
Questi sono poi affiancati da sistemi di Management del Codice Sorgente, che oltre a tenere traccia della versione permettono anche di tracciare i bug e la documentazione.
Fossil è una semplice soluzione integrata che vi fornisce tutto questo in un unico pacchetto.
È già estremamente utile per lavorare da soli, e permette di usare lo stesso strumento per collaborare, coordinando il lavoro di varie persone che lavorano allo stesso progetto, online ed offline.
Le collaborazioni avvengono tramite un server centrale che fa da punto di scambio.
Potete anche ospitarlo su di un vostro computer, il server è lo stesso programma che avete già scaricato.
Ogni modifica che farete sarà automaticamente registrata sul server in automatico, e passata agli altri quando si collegheranno.
cit:
se vale la pena di essere fatto, vale la pena di essere messo sotto controllo di versione
si può scaricare dal suo sito web: Fossil-SCM.
È un programma free ed open source, cross-platform e contenuto in un unico file, quindi è molto facile da spostare in giro.
Il vostro repository è contenuto in un unico file, un database che contiene tutte le informazioni rilevanti (new).
Fare il backup dell'intero repository con TUTTE le informazioni è semplicemente copiare il file in giro. basta tenerlo nella cartella di sincronizzazione di dropbox ed il problema è risolto.
Potete estrarne l'ultima versione in una cartella (open), modificarla e, quando siete soddisfatti del risultato, inserirla come una versione successiva (commit).
Potete usare il controllo di versione per qualsiasi file text-based che volete, non soltanto il codice.
Ad esempio tenere la propria tesi ed il testo dei propri articoli sotto controllo di versione è generalmente una buona idea.
Ogni volta che vi allontanate dall'usare file di teste, perdete tutta la potenza di questi sistemi di controllo, ed è un vantaggio insostituibile!
import os
import contextlib
os.chdir(os.path.expanduser('~/lavoro/fossilexample'))
with contextlib.suppress(FileExistsError):
os.mkdir('../fossilexample/')
os.chdir('../fossilexample/')
print(os.getcwd())
with contextlib.suppress(FileNotFoundError):
os.remove('mytestrepo.fossil')
import shutil
shutil.rmtree('working_directory', ignore_errors=True)
print(os.listdir('.'))
!fossil init mytestrepo.fossil
%ls
%mkdir -p working_directory
%cd working_directory
%pwd
!fossil open ../mytestrepo.fossil
%%writefile test.txt
This is going to be my documentation
!fossil status
!fossil extra
!fossil add test.txt
!fossil status
!fossil commit -m "il primo file di un grande progetto!"
!fossil status
a questo punto potete vedere cosa succere lanciando il comando
fossil ui
%%writefile test.txt
This is going to be my documentation
I'm adding more lines: the more, the merrier!
!fossil status
!fossil diff test.txt
!fossil commit -m "espansa la documentazione"
mi sono accorto di aver fatto un errore!
come posso rimediare?
Per prima cosa, lascio traccia della decisione: apro un ticket.
!fossil help revert
!fossil revert -r 2dab9716e9 test.txt
!fossil status
!fossil diff test.txt
!fossil commit -m "riportato l'ordine nel repository!"
ora non mi rimane che chiudere il ticket e continuare il mio lavoro
una funzionalità molto potente per il controllo di versione è la possibilità di fare branching.
Questo significa che nel mio database esistono nello stesso momento due versioni diverse dello stesso progetto, e posso passare da un all'altra senza problemi.
Un grosso vantaggio del modello di DVCS di fossil è che posso usare diverse cartelle per diversi branch, ed avere il tutto sincronizzato!
avete appena raggiunto un risultato pubblicabile con le vostre analisi, e volete prepararvi per pubblicarle.
Questo significa che non altererete più il codice in modo sostanziale (volete mantenere l'integrità dei risultati), ma magari aggiusterete i grafici ed i report.
Allo stesso momento, i vostri collaboratori vi chiedono di fare delle modifiche piuttosto importanti del codice. Come potete fare?
Usando due diverse branch siete in grado di dividere il lavoro senza fare confusione, ma mantenendo tutto sempre sotto controllo (e con la possibilità di far passare i risultati da un branch all'altro con revert).
!fossil help checkout
per comodità faremo il cambio di branch nella stessa directory, ma in generale creeremmo una seconda directory, apriremmo il repository e faremmo il checkout della versione che ci interessa.
In questo caso, ritorniamo allo stato iniziale del repository.
!fossil checkout e17a3d4a58
il repository è vuoto come l'abbiamo lasciato due commit fa.
ls
%%writefile test.txt
this is an alternative history
!fossil add test.txt
!fossil commit -m "nuova storia"
!fossil commit --allow-fork -m "nuova storia"
notate che viene registrato anche il cambiamento di nome del branch!
Un'altra operazione molto comune è rinominare o eliminare un file.
Un comportamento curioso di fossil è che registra il cambiamento ma non lo attua: dovete esplicitamente rinominare il file dalla linea di comando
!fossil mv test.txt test2.txt
!ls
!mv test.txt test2.txt
!fossil status
!fossil commit -m "cambiato il nome del file"
!rm test2.txt
!fossil rm test2.txt
%%writefile test3.txt
crazy experiments!
!fossil add test3.txt
!fossil commit -m "ultimo commit del branch sperimentale"
Ora, visto che ci piace renderci la vita complicata, vogliamo unire i due branch.
Questo può servire quando stiamo facendo delle modifiche sperimentali ad una parte della nostra analisi e non vogliamo includerlo fintanto che non siamo sicuri che stia funzionando correttamente.
Per fare questo dobbiamo usare il comando merge, ma prima dobbiamo metterci nella linea principale che vogliamo mantenere (visto che l'altra poi sparirà) con un checkout.
Questo risulta molto più facile se avete due cartelle separate. Se state usando la stessa, controllate due volte prima di fare il checkout!
!fossil checkout 488479276d
!fossil merge 47cc19ae1f --dry-run
!fossil merge 47cc19ae1f
!fossil status
!fossil commit -m "le due storie sono finalmente unite!"
Il file che abbiamo modificato all'inizio, test.txt, dava problemi per il merge perchè creato indipendentemente nei due branch. L'unica soluzione che ho trovato è stata gestire il merge a mano, in pratica creare un nuovo file da zero ed eventualmente riempirlo con il contenuto del vecchio.